/*
 * <one line to give the program's name and a brief idea of what it does.>
 * Copyright (C) 2013  <copyright holder> <email>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */
#include <cstdio>

#include "AlignViewer.h"
#include "ui_AlignViewer.h"

#include <indicom.h>

AlignViewer::AlignViewer(): QWidget(), INDI::BaseClient()
{
    QGraphicsSimpleTextItem *sccard;
    
    indihost=(char *)DEFAULT_HOST;
    indiport=DEFAULT_PORT;
    indidevice=NULL;
    telescopecoords=NULL;
    alignedcoords=NULL;
    aligndata=NULL;
    alignblob=NULL;
    pointset = NULL;
    faces=NULL;
    
    this->setServer(indihost, indiport);
    ui=new Ui::AlignViewer();
    ui->setupUi(this);
    
    mountdpy = new MountDisplay();
    mountdpy->setupUi(ui->framemount);
    aligneddpy = new MountDisplay();
    aligneddpy->setupUi(ui->framealigned);
 


    scene.setBackgroundBrush(QColor(0, 0, 0, 255));
    scqpen=new QPen(QColor(255,255,255,255));
    scqpen->setBrush(QBrush(QColor(255,255,255,255)));
    scqpenblue.setColor(QColor(0,0,200,255));
    scqpengreen.setColor(QColor(0,200,0,255));
    scqpenyellow.setColor(QColor(255,255,102,255));
    scqpenorange.setColor(QColor(250,105,0, 255));
    scqpenbrightorange.setColor(QColor(255,131,0, 255));
    
    gvwidth=ui->graphicsView->width();
    gvheight=ui->graphicsView->height();
    // Ellipse centered in view, x axis is towards right, y axis is downwards
    schorizon=scene.addEllipse(-gvwidth/2 + HMARGIN, -gvheight/2 + VMARGIN, gvwidth-(2*HMARGIN), gvheight-(2*VMARGIN), QPen(QColor(255,255,255,255)));
    sccard=scene.addSimpleText("N");
    sccard->setPos(0, -gvheight/2 +2 );
    sccard->setPen(*scqpen);
    sccard=scene.addSimpleText("W");
    sccard->setPos(gvwidth/2 - 16, 0);
    sccard->setPen(*scqpen);
    sccard=scene.addSimpleText("S");
    sccard->setPos(0, gvheight/2 -22 );
    sccard->setPen(*scqpen);
    sccard=scene.addSimpleText("E");
    sccard->setPos(-gvwidth/2 + 2, 0);
    sccard->setPen(*scqpen);
    polereticle.moveTo(0, -POLE_RETICLE / 2);
    polereticle.lineTo(0, POLE_RETICLE / 2);
    polereticle.moveTo(-POLE_RETICLE / 2, 0);
    polereticle.lineTo(POLE_RETICLE / 2, 0);
    scpolereticle=scene.addPath(polereticle, *scqpen);
    //scpolereticle->setPos(-POLE_RETICLE, -POLE_RETICLE);
    
    sclon=scene.addSimpleText("Lon: --.--");
    sclon->setPos(gvwidth/2 - 110, -gvheight/2 + 2);
    sclon->setPen(*scqpen);
    sclat=scene.addSimpleText("Lat: --.--");
    sclat->setPos(gvwidth/2-110, -gvheight/2 + 17);
    sclat->setPen(*scqpen);
    sctelescope=scene.addEllipse(-TELESCOPE_RETICLE, -TELESCOPE_RETICLE, 2*TELESCOPE_RETICLE, 2*TELESCOPE_RETICLE, scqpenorange);
    scaligned=scene.addEllipse(-ALIGNED_RETICLE, -ALIGNED_RETICLE, 2*ALIGNED_RETICLE, 2*ALIGNED_RETICLE, scqpenbrightorange);  
    /*
    sclst=scene.addSimpleText("LST: --:--:--");
    sclst->setPos(-gvwidth/2 + 2, -gvheight/2 + 2);
    sclst->setPen(*scqpen);
    sctelescopelabel=scene.addSimpleText("Telescope");
    sctelescopelabel->setPos(-gvwidth/2 +2, gvheight/2 -52);
    sctelescopelabel->setPen(scqpenblue);
    sctelescopealt=scene.addSimpleText("alt: --.--");
    sctelescopealt->setPos(-gvwidth/2 +2, gvheight/2 -37);
    sctelescopealt->setPen(*scqpen);
    sctelescopeaz=scene.addSimpleText("az: ---.--");
    sctelescopeaz->setPos(-gvwidth/2 +2, gvheight/2 -22);
    sctelescopeaz->setPen(*scqpen);
    sctelescope=scene.addEllipse(0, 0, 2 * TELESCOPE_RETICLE, 2 * TELESCOPE_RETICLE, *scqpen);
    scalignedlabel=scene.addSimpleText("Aligned");
    scalignedlabel->setPos(gvwidth/2 -80, gvheight/2 -52);
    scalignedlabel->setPen(scqpengreen);    
    scalignedalt=scene.addSimpleText("alt: --.--");
    scalignedalt->setPos(gvwidth/2 -100, gvheight/2 -37);
    scalignedalt->setPen(*scqpen);
    scalignedaz=scene.addSimpleText("az: ---.--");
    scalignedaz->setPos(gvwidth/2 -100, gvheight/2 -22);
    scalignedaz->setPen(*scqpen);
    scaligned=scene.addEllipse(0, 0, 2 * ALIGNED_RETICLE, 2 * ALIGNED_RETICLE, *scqpen);   

    //QObject::connect(&timer, SIGNAL(timeout()), this, SLOT(repaint()));
    //timer.start(TimerFreq);
*/
    ui->graphicsView->setScene(&scene);
    
    
    // Indi callbacks
    connect(this, SIGNAL(obschanged(double,double)), this, SLOT(changeobs(double,double)));
    connect(this, SIGNAL(lstchanged(double)), this, SLOT(changelst(double)));
    connect(this, SIGNAL(telescopecoordschanged(double,double)), this, SLOT(changetelescopecoords(double,double)));
    connect(this, SIGNAL(alignedcoordschanged(double,double)), this, SLOT(changealignedcoords(double,double)));
    
    connect(this, SIGNAL(pointsetchanged(std::vector<AlignPoint>*)), this, SLOT(changepointset(std::vector<AlignPoint>*)));
    connect(this, SIGNAL(faceschanged(std::vector<Face>*)), this, SLOT(changefaces(std::vector<Face>*)));
    
    // Menu buttons
    connect(ui->pushButtonConnect, SIGNAL(clicked()), this, SLOT(connectMount()));
}

bool AlignViewer::close()
{
    //std::printf("Closing...");
    return QWidget::close();
}

void AlignViewer::repaint()
{
  ui->graphicsView->repaint();
}

void AlignViewer::connectMount()
{
  //std::printf("Connecting...");
  IDLog("Connecting...\n");
  INDI::BaseClient::watchDevice(DEFAULT_DEVICE_NAME);
  INDI::BaseClient::connectServer();
}

void AlignViewer::disconnectMount()
{
  //std::printf("Connecting...");
  IDLog("Disconnecting...\n");
  INDI::BaseClient::disconnectServer();
}

void AlignViewer::serverConnected()
{
  ui->pushButtonConnect->setText("Disconnect");
  disconnect(ui->pushButtonConnect, SIGNAL(clicked()), this, SLOT(connectMount()));
  connect(ui->pushButtonConnect, SIGNAL(clicked()), this, SLOT(disconnectMount()));
}

void AlignViewer::serverDisconnected(int exit_code)
{
  ui->pushButtonConnect->setText("Connect");
  disconnect(ui->pushButtonConnect, SIGNAL(clicked()), this, SLOT(disconnectMount()));
  connect(ui->pushButtonConnect, SIGNAL(clicked()), this, SLOT(connectMount()));
  indidevice=NULL;
}  

void AlignViewer::setTelescopePropertyName(char *name)
{
  telescopecoordsname = name;
}

void AlignViewer::setAlignedPropertyName(char *name)
{
  alignedcoordsname = name;
}

//Slots
void AlignViewer::changeobs(double lat, double lon)
{
  char sexa[13];	
  fs_sexa(sexa, lat, 2, 3600);
  sclat->setText(QString("Lat: ")+QString(sexa));
  fs_sexa(sexa, lon, 3, 3600);
  sclon->setText(QString("Lon: ")+QString(sexa));
  QPointF newpos=getposAltAz(lat, 0);
  scpolereticle->setPos(newpos); 
}

void AlignViewer::changelst(double lst)
{
  mountdpy->setLST(lst);
  aligneddpy->setLST(lst);
}

// Argh mixed telescope/target and aligned/telescope
void AlignViewer::changetelescopecoords(double tra, double tdec)
{
  telescope_ra = tra;
  telescope_dec = tdec;
  toAltAz(tra, tdec, obs_lst, obs_lon, obs_lat, &telescope_alt, &telescope_az);
  mountdpy->changeEquatorialCoords(tra, tdec);
  mountdpy->changeHorizontalCoords(telescope_alt, telescope_az);
  QPointF newpos=getposAltAz(telescope_alt, telescope_az);
  //newpos-=QPoint(TELESCOPE_RETICLE, TELESCOPE_RETICLE);
  sctelescope->setPos(newpos);
}

void AlignViewer::changealignedcoords(double ara, double adec)
{
  aligned_ra=ara;
  aligned_dec = adec;
  toAltAz(ara, adec, obs_lst, obs_lon, obs_lat, &aligned_alt, &aligned_az);
  aligneddpy->changeEquatorialCoords(ara, adec);
  aligneddpy->changeHorizontalCoords(aligned_alt, aligned_az);
  QPointF newpos=getposAltAz(aligned_alt, aligned_az);
  //newpos-=QPoint(ALIGNED_RETICLE, ALIGNED_RETICLE);
  scaligned->setPos(newpos);
}

void AlignViewer::changepointset(vector< AlignViewer::AlignPoint >* ps)
{
  IDLog("Cleaning old pointset\n");
  if (pointset) {
    for (std::vector<AlignPoint>::iterator it = pointset->begin() ; it != pointset->end(); ++it) {
      scene.removeItem((*it).telescopeitem);
      scene.removeItem((*it).targetitem);
    }
    pointset->clear();
    delete(pointset);
  }
  IDLog("Loading new pointset\n");
  pointset=ps;
  for (std::vector<AlignPoint>::iterator it = pointset->begin() ; it != pointset->end(); ++it) {
    //IDLog("Load alignment point: %f %f %f %f %f\n", aligndata.lst, aligndata.targetRA, aligndata.targetDEC, 
    //  aligndata.telescopeRA, aligndata.telescopeDEC);
    QPointF newpos=getposAltAz(it->target_alt, it->target_az);
    newpos-=QPoint(POINTSET_TARGET_RETICLE, POINTSET_TARGET_RETICLE);
    it->targetitem=scene.addEllipse(newpos.x(), newpos.y(), 2 * POINTSET_TARGET_RETICLE, 2 * POINTSET_TARGET_RETICLE, scqpenblue); 
    it->targetitem->setToolTip(QString::number(it->index));
    newpos=getposAltAz(it->telescope_alt, it->telescope_az);
    newpos-=QPoint(POINTSET_TELESCOPE_RETICLE, POINTSET_TELESCOPE_RETICLE);
    it->telescopeitem=scene.addEllipse(newpos.x(), newpos.y(), 2 * POINTSET_TELESCOPE_RETICLE, 2 * POINTSET_TELESCOPE_RETICLE, scqpengreen);   
   }
}

void AlignViewer::changefaces(vector< AlignViewer::Face >* nf)
{
  IDLog("Cleaning old faces\n");
  if (faces) {
    for (std::vector<Face>::iterator it = faces->begin() ; it != faces->end(); ++it) {
      for (std::vector<QGraphicsItem *>::iterator git = it->g.begin(); git != it->g.end(); ++git) {
	scene.removeItem((*git));
      }
    }
    faces->clear();
    delete(faces);
  }
  IDLog("Loading new faces\n");
  faces=nf;
  
  for (std::vector<Face>::iterator it = faces->begin() ; it != faces->end(); ++it) {
    int gcount = 0,vcount=0, i, next;
    AlignPoint *p;
    p=findPointIndex(it->index[0]);
    if (p==NULL) {IDLog("Can't find point %d\n", it->index[0]); return;}
    it->v[0]=p;
     p=findPointIndex(it->index[1]);
    if (p==NULL) {IDLog("Can't find point %d\n", it->index[1]); return;}
    it->v[1]=p;
    p=findPointIndex(it->index[2]);
    if (p==NULL) {IDLog("Can't find point %d\n", it->index[2]); return;}
    it->v[2]=p;
    
    vcount = (*it).v.size();
    for (i=0; i < vcount; i++) {
     AlignPoint *p0, *p1;
     next = i + 1;
     if (next == vcount) next = 0;
     p0=(*it).v[i];
     p1=(*it).v[next];
     if ((p0 == NULL) || (p1==NULL)) {IDLog("NULL found i=%d next=%d\n", i, next); continue;}
     IDLog("gcount %d p%d %g %g p%d %g %g\n", gcount, p0->index, p0->target_alt, p0->target_az, p1->index, p1->target_alt, p1->target_az);
     
     QPainterPath *qp=getArc(p0->target_alt, p0->target_az, p1->target_alt, p1->target_az);
     QGraphicsItem *sp = scene.addPath(*qp, scqpenyellow);
     (*it).g[gcount++]=sp;
     
   }
  }
  
}

// INDI Client
void AlignViewer::newDevice(INDI::BaseDevice *dp)
{
  //std::printf("new device %s\n", dp->getDeviceName());
  IDLog("new device %s\n", dp->getDeviceName());
  if (!strcmp(dp->getDeviceName(), DEFAULT_DEVICE_NAME))
  {
   indidevice = dp; 
  }
}

void AlignViewer::newProperty(INDI::Property* property)
{
 
  //IDLog("new property %s %d\n", property->getName(), property->getType());
   
  if (not strcmp(property->getName(), "GEOGRAPHIC_COORD")) {
    obs_lat=property->getNumber()->np[0].value;
    obs_lon=property->getNumber()->np[1].value;
    emit obschanged(obs_lat, obs_lon);
  }
  //if (not indidevice) return;
  if (property->getType() == INDI_NUMBER) {
    if (not strcmp(property->getName(), DEFAULT_TELESCOPE_COORD)) {
      telescopecoords=property;
    }
    if (not strcmp(property->getName(), DEFAULT_ALIGNED_COORD)) {
      alignedcoords=property;
    }
  }
  if (property->getType() == INDI_BLOB) {
    if (not strcmp(property->getName(), DEFAULT_ALIGN_DATA)) {
       aligndata=property;
       alignblob=IUFindBLOB(property->getBLOB(), DEFAULT_POINTSET);
       if (alignblob) { 
	 //newBLOB(alignblob);
	 IDLog("Got Align blob data\n");
           //Receive BLOB align data
       }
      if (aligndata)
	this->setBLOBMode(B_ALSO, indidevice->getDeviceName(), NULL);
    }     
  }
}

void AlignViewer::removeProperty(INDI::Property *property) 
{
  
}

void AlignViewer::newBLOB(IBLOB *bp)
{
  LilXML *lp = newLilXML();
  XMLEle *root=NULL;
  char *buf;
  char errmsg[512];

  if (!strcmp(bp->name, "POINTLIST")) { 
    AlignPoint alignpoint;
    XMLEle *alignxml, *sitexml;
    XMLAtt *ap;
    std::vector<AlignPoint> *newpointset;
    IDLog("Receiving PointSet Blob\n");
    buf = (char *)bp->blob;
    do {
      root = readXMLEle (lp, *buf++, errmsg);
    } while (!root && !errmsg[0]);
 
    delLilXML (lp);
    if ((not root) || errmsg[0]) {
      IDLog("Error in blob: %s\n", errmsg);
      return;
    }
    if (!strcmp(tagXMLEle(nextXMLEle(root, 1)), "aligndata")) {
      IDLog("Not an alignement data blob");
      return;
    }

    newpointset=new std::vector<AlignPoint>;
    sitexml=findXMLEle(root, "site");
    ap = findXMLAtt(sitexml, "lat");
    if (!ap) pointsetlat=0.0;
    else sscanf(valuXMLAtt(ap), "%lf", &pointsetlat);
    ap = findXMLAtt(sitexml, "lon");
    if (!ap) pointsetlon=0.0;
    else sscanf(valuXMLAtt(ap), "%lf", &pointsetlon);
    alignxml=nextXMLEle(sitexml, 1);
    while (alignxml) {
      //IDLog("synctime %s\n", pcdataXMLEle(findXMLEle(alignxml, "synctime")));
      sscanf(pcdataXMLEle(findXMLEle(alignxml, "index")), " %d ", &alignpoint.index);
      sscanf(pcdataXMLEle(findXMLEle(alignxml, "synctime")), " %lf ", &alignpoint.lst);
      sscanf(pcdataXMLEle(findXMLEle(alignxml, "celestialra")), "%lf", &alignpoint.targetRA);
      sscanf(pcdataXMLEle(findXMLEle(alignxml, "celestialde")), "%lf", &alignpoint.targetDEC);
      sscanf(pcdataXMLEle(findXMLEle(alignxml, "telescopera")), "%lf", &alignpoint.telescopeRA);
      sscanf(pcdataXMLEle(findXMLEle(alignxml, "telescopede")), "%lf", &alignpoint.telescopeDEC);
      //IDLog("Load alignment point: %f %f %f %f %f\n", aligndata.lst, aligndata.targetRA, aligndata.targetDEC, 
      //  aligndata.telescopeRA, aligndata.telescopeDEC);
      toAltAz(alignpoint.telescopeRA, alignpoint.telescopeDEC, alignpoint.lst, pointsetlon, pointsetlat, &alignpoint.telescope_alt, &alignpoint.telescope_az);
      toAltAz(alignpoint.targetRA, alignpoint.targetDEC, alignpoint.lst, pointsetlon, pointsetlat, &alignpoint.target_alt, &alignpoint.target_az);  
      newpointset->insert(newpointset->end(), alignpoint);
      //IDLog("New point %d\n", alignpoint.index);
      alignxml=nextXMLEle(sitexml, 0);
    }
    emit pointsetchanged(newpointset);
  }
  if (!strcmp(bp->name, "TRIANGULATION")) { 
    AlignPoint alignpoint;
    XMLEle *facexml, *vertexxml;
    XMLAtt *ap;
    std::vector<Face> *newfaces;
    IDLog("Receiving Triangulation Blob\n");
    buf = (char *)bp->blob;
    do {
      root = readXMLEle (lp, *buf++, errmsg);
    } while (!root && !errmsg[0]);
 
    delLilXML (lp);
    if ((not root) || errmsg[0]) {
      IDLog("Error in blob: %s\n", errmsg);
      return;
    }
    XMLEle *testvoid=nextXMLEle(root,1);
    if (testvoid && !strcmp(tagXMLEle(nextXMLEle(root, 1)), "triangulation")) {
      IDLog("Not a triangulation data blob");
      return;
    }

    newfaces=new std::vector<Face>;

    facexml=nextXMLEle(root, 1);
    while (facexml) {
      int vindex0, vindex1, vindex2;
 
      vertexxml=nextXMLEle(facexml, 1);
      sscanf(pcdataXMLEle(vertexxml), " %d", &vindex0);

      vertexxml=nextXMLEle(facexml, 0);
      sscanf(pcdataXMLEle(vertexxml), " %d", &vindex1);

      vertexxml=nextXMLEle(facexml, 0);
      sscanf(pcdataXMLEle(vertexxml), " %d", &vindex2);
 
      newfaces->insert(newfaces->end(), Face(vindex0, vindex1, vindex2));
      //IDLog("Load alignment point: %f %f %f %f %f\n", aligndata.lst, aligndata.targetRA, aligndata.targetDEC, 
      //  aligndata.telescopeRA, aligndata.telescopeDEC);
      toAltAz(alignpoint.telescopeRA, alignpoint.telescopeDEC, alignpoint.lst, pointsetlon, pointsetlat, &alignpoint.telescope_alt, &alignpoint.telescope_az);
      toAltAz(alignpoint.targetRA, alignpoint.targetDEC, alignpoint.lst, pointsetlon, pointsetlat, &alignpoint.target_alt, &alignpoint.target_az);  
      facexml=nextXMLEle(root, 0);
    }
    emit faceschanged(newfaces);
  }
}

void AlignViewer::newSwitch(ISwitchVectorProperty *svp) 
{
  
}

void AlignViewer::newNumber(INumberVectorProperty *nvp)
{
  
  if (not indidevice) return;
  
  if (not strcmp(nvp->name, "GEOGRAPHIC_COORD")) {
    obs_lat=nvp->np[0].value;
    obs_lon=nvp->np[1].value;
    emit obschanged(obs_lat, obs_lon);
  }
  
  if (not strcmp(nvp->device, indidevice->getDeviceName())) {
    if (not strcmp(nvp->name, "TIME_LST")) {
      obs_lst=nvp->np[0].value;
      emit lstchanged(obs_lst);
    }
    if ((not telescopecoords) || (not alignedcoords)) return;
    if (not strcmp(nvp->name, telescopecoords->getName())) {
      //IDLog("New telescope coords %g %g\n", nvp->np[0].value, nvp->np[1].value);
      telescope_ra=nvp->np[0].value;
      telescope_dec=nvp->np[1].value;
      emit telescopecoordschanged(telescope_ra, telescope_dec);
      
    }
    if (not strcmp(nvp->name, alignedcoords->getName())) {
      //IDLog("New telescope coords %g %g\n", nvp->np[0].value, nvp->np[1].value);
      aligned_ra=nvp->np[0].value;
      aligned_dec=nvp->np[1].value;
      emit alignedcoordschanged(aligned_ra, aligned_dec);

    } 
  }
 
}

void AlignViewer::newMessage(INDI::BaseDevice *dp, int messageID)
{
  
}

void AlignViewer::newText(ITextVectorProperty *tvp)
{
  
}

void AlignViewer::newLight(ILightVectorProperty *lvp)
{
  
}

AlignViewer::AlignPoint *AlignViewer::findPointIndex(int index)
{
  if (pointset == NULL) {IDLog("PointSet is NULL\n"); return NULL;}
  std::vector<AlignViewer::AlignPoint>::iterator it=pointset->begin();
  while (it < pointset->end()) {
   if (it->index == index) return &(*it);
   it++;
  }
  return NULL;
}

void AlignViewer::toAltAz(double ra, double dec, double lst, double lon, double lat, double *alt, double *az)
{
  struct ln_equ_posn lnradec;
  struct ln_lnlat_posn lnobserver;
  struct ln_hrz_posn lnaltaz; 
 
  lnradec.ra =(ra * 360.0) / 24.0;
  lnradec.dec =dec;
  lnobserver.lat=lat;
  lnobserver.lng=lon;
  lst -= lon / 15.0;
  ln_get_hrz_from_equ_sidereal_time(&lnradec, &lnobserver, lst, &lnaltaz);
  /* libnova measures azimuth from south towards west, kstars from north towards east */
  *az=range360(lnaltaz.az + 180);
  *alt=lnaltaz.alt; 
}

double AlignViewer::range360(double r) {
  double res = r;
  while (res<0.0) res+=360.0;
  while (res>=360.0) res-=360.0;
  return res;
} 

QPointF AlignViewer::getposAltAz(double alt, double az) 
{
  double x, y;
  double radius = schorizon->rect().width() / 2;
  double tphi = - tan(((90 - alt) * M_PI)/ 360.0);
  //x = radius * cos(((90-az) * 2.0 * M_PI)/360.0) * cos((alt * 2.0 * M_PI)/ 360.0);
  //y = radius * sin(((90-az) * 2.0 * M_PI)/360.0) * cos((alt * 2.0 * M_PI)/ 360.0);
  // Azimuthal stereographic: http://www-history.mcs.st-and.ac.uk/Projects/Hoyer/S3.html
  x = radius * cos(((270-az) * 2.0 * M_PI)/360.0) * (-tphi); // reverse E/W
  y = radius * sin(((270-az) * 2.0 * M_PI)/360.0) * (-tphi); // y downwards
  return QPointF(x, y);
}

QPainterPath* AlignViewer::getArc(double alt1, double az1, double alt2, double az2)
{
  QPointF p1, antip1;
  QPointF p2;
  double d, xcenter, ycenter;
  double a, b, a1, b1;
  double caz1, caz2;
  double startAngle, sweeplen;
  QPainterPath *result=new QPainterPath();
  p1 = getposAltAz(alt1, az1);
  antip1=getposAltAz(-alt1, range360(180.0 + az1));
  p2=getposAltAz(alt2 ,az2);
  /* Hard to draw great circle stereographic projection with Qt 
  // circle p1, p2 ,p3
  a = (antip1.x() - p1.x()) /  (antip1.y() - p1.y());
  b = (((antip1.x() * antip1.x()) - (p1.x() * p1.x())) + ((antip1.y() * antip1.y()) - (p1.y() * p1.y()))) / ( 2.0 * (antip1.y() - p1.y()));
  a1 = (p2.x() - antip1.x()) /  (p2.y() - antip1.y());
  b1 = (((p2.x() * p2.x()) - (antip1.x() * antip1.x())) + ((p2.y() * p2.y()) - (antip1.y() * antip1.y()))) / ( 2.0 * (p2.y() - antip1.y()));  
  xcenter = (b - b1) / (a1 - a);
  ycenter = (a * xcenter + b);  
  d = 2.0 * sqrt(((p1.x() - xcenter) * (p1.x() - xcenter)) + ((p1.y() - ycenter) * (p1.y() - ycenter)));
  IDLog("GetArc(%g, %g, %g, %g): p1(%g,%g) p2(%g,%g) antip1(%g,%g) xc= %g yc=%g d =%g\n",alt1, az1, alt2, az2, p1.x(), p1.y(), p2.x(),p2.y(), antip1.x(), antip1.y(),  xcenter, ycenter, d);
  caz1=-atan2(p1.y() - ycenter, p1.x() - xcenter) * 180.0 / M_PI; //Qt angles ??
  caz2=-atan2(p2.y() - ycenter, p2.x() - xcenter) * 180. / M_PI;
  /*
  /*if (caz1 < caz2) 
  {
    startAngle=caz1;
    sweeplen = caz2 - caz1;
    result->moveTo(p1);
  } else 
  {
    startAngle=caz2;
    sweeplen = caz1 - caz2;
    result->moveTo(p2);  
  }
  */
  /*
  startAngle=caz1;
  sweeplen=caz2-caz1;
  result->moveTo(p1);
  result->arcTo(xcenter - d/2, ycenter - d/2, d, d, startAngle, sweeplen);
  */
  result->moveTo(p1);
  result->lineTo(p2);
  return result;
}